﻿using SharpDX;
using System;
using System.Diagnostics;

namespace MikadoShooter
{
    public static class CollisionCheckHelper
    {
        //Ball hit a line?
        public static Vector2? IsCollision(Vector4 target1, Vector4 target2, Vector4 ball1, Vector4 ball2)
        {
            float d;
            Vector3 vec1 = GetValues(ball1, ball2);
            Vector3 vec2 = GetValues(target1, target2);

            //parallel line
            if (Math.Abs(d = vec1.Y * vec2.X - vec2.Y * vec1.X) < float.Epsilon) 
            {
                Debug.WriteLine("Wall check - Parallel lines");
                return null;
            }

            //Intersection point
            Vector2 hit = Intersection(vec1, vec2, d);


            //Not the startpoint
            if ( ball1 == new Vector4(hit, ball1.Z, ball1.W) )
            {
                Debug.WriteLine("Wall check - Skipping startpos");
                return null;
            }

            //Check for hit
            return Math.Min(target1.X, target2.X) <= hit.X && hit.X <= Math.Max(target1.X, target2.X) &&
                   (Math.Min(target1.Y, target2.Y) <= hit.Y && hit.Y <= Math.Max(target1.Y, target2.Y)) &&
                   (Math.Min(ball1.X, ball2.X) <= hit.X && hit.X <= Math.Max(ball1.X, ball2.X)) &&
                   (Math.Min(ball1.Y, ball2.Y) <= hit.Y && hit.Y <= Math.Max(ball1.Y, ball2.Y))
                       ? (Vector2?) hit : null;
        }

        //Ball hit a target line?
        public static Collision IsCollision(Vector4Target targets, Vector4 ball1, Vector4 ball2, Vector4 ballColor)
        {
            Collision collision = new Collision(null, false,Vector2.Zero,null);
            
            //Ball Point
            Vector3 vec1 = GetValues(ball1, ball2);

            for (int i = 0; i < targets.Data.Length; i += 4)
            {
                //Skip already removed lines!
                if (targets.IsRemoved[i / 2 + 0] && targets.IsRemoved[i / 2 + 1])
                    continue;

                //Target line
                Vector3 vec2 = GetValues(targets.Data[i], targets.Data[i + 2]);

                //parallel line
                float d;
                if (Math.Abs(d = vec1.Y * vec2.X - vec2.Y * vec1.X) < float.Epsilon) //parallel lines
                {
                    Debug.WriteLine("Line check - Parallel lines");
                    continue;
                }

                //Intersection points.
                Vector2 hit = Intersection(vec1, vec2, d);

                //Closet to the startpoint should be the first hit
                float dist = Vector2.Distance(hit, (Vector2) ball1);

                //In Line check
                if (Math.Min(targets.Data[i].X, targets.Data[i + 2].X) <= hit.X &&
                    hit.X <= Math.Max(targets.Data[i].X, targets.Data[i + 2].X) &&
                    (Math.Min(targets.Data[i].Y, targets.Data[i + 2].Y) <= hit.Y &&
                     hit.Y <= Math.Max(targets.Data[i].Y, targets.Data[i + 2].Y)) &&
                    (Math.Min(ball1.X, ball2.X) <= hit.X && hit.X <= Math.Max(ball1.X, ball2.X)) &&
                    (Math.Min(ball1.Y, ball2.Y) <= hit.Y && hit.Y <= Math.Max(ball1.Y, ball2.Y)) &&
                    (collision.Distance == null || collision.Distance > dist))
                {
                    collision = targets.Data[i + 1] == ballColor 
                        ? new Collision(new[] {i, i + 2}, true, hit, dist)
                        : new Collision(null, true, hit, dist);
                }
            }

            return collision;
        }

        private static Vector2 Intersection(Vector3 vec1, Vector3 vec2, float D)
        {
            return new Vector2(vec2.X * vec1.Z - vec1.X * vec2.Z,
                               vec1.Y * vec2.Z - vec2.Y * vec1.Z) / D;
        }

        private static Vector3 GetValues(Vector4 vec1, Vector4 vec2)
        {
            return new Vector3(vec2.X - vec1.X, 
                               vec1.Y - vec2.Y, 
                               (vec1.Y - vec2.Y) * vec1.X + (vec2.X - vec1.X) * vec1.Y);
        }
    }
}